/*
 * 组件注释
 * @Author: machinist_wq
 * @Date: 2022-05-11 17:42:45
 * @LastEditors: machinist_wq
 * @LastEditTime: 2022-11-07 08:56:24
 * @Description: 这个文件里面的函数都是发生在一个fiber节点内的，
 * 这里的链表指的是fiber节点上存储数据的hook的链表
 * 整个fiber的链表在src/react/ReactFiberWorkloop.js中
 * 既往不恋！当下不杂！未来不迎！！！
 */

import { scheduleUpdateOnFiber } from "./ReactFiberWorkloop";
import { areHookInputsEqual, HookLayout, HookPassive, isFn } from "./utils";
let currentlyRenderingFiber = null; // 当前的fiber节点
let workInProgessHook = null; // hook链表的最后一个
let currentHook = null; // 上一次的hook

export function renderWithHooks(wip) {
  // 初始化
  currentlyRenderingFiber = wip;
  currentlyRenderingFiber.memorizedState = null;
  currentlyRenderingFiber.updateQueueOfLayout = [];
  currentlyRenderingFiber.upDateQueueOfEffect = [];
  workInProgessHook = null;
}

export function updateWorkInProgressHook() {
  let hook = null;
  //判断是初次渲染还是更新
  let current = currentlyRenderingFiber.alternate;
  if (current) {
    // 更新（我们需要从hook链表上取下当前需要的hook）
    currentlyRenderingFiber.memorizedState = current.memorizedState; // 将老的hook链表更新到新的链表上来
    // 要判断是不是头指针
    if (workInProgessHook) {
      hook = workInProgessHook = workInProgessHook.next;
      currentHook = currentHook.next;
    } else {
      // head hook
      hook = workInProgessHook = current.memorizedState;
      currentHook = current.memorizedState;
    }
  } else {
    // 初次渲染
    currentHook = null;
    hook = {
      memorizedState: null,
      next: null,
    };

    // 下面的步骤是将hook保存在fiber节点上
    // 要判断是不是头指针
    if (workInProgessHook) {
      // 因为尾指针不为空所以不是头指针
      workInProgessHook = workInProgessHook.next = hook;
    } else {
      // head hook
      workInProgessHook = currentlyRenderingFiber.memorizedState = hook;
    }
  }

  return hook;
}

export function useReducer(reducer, initialState) {
  const hook = updateWorkInProgressHook();
  if (!currentlyRenderingFiber.alternate) {
    hook.memorizedState = initialState;
  }

  //! 触发deps更新
  const dispatch = action => {
    hook.memorizedState = reducer
      ? reducer(hook.memorizedState, action)
      : isFn(action)
      ? action(hook.memorizedState)
      : action;
    scheduleUpdateOnFiber(currentlyRenderingFiber);
  };
  return [hook.memorizedState, dispatch];
}

export function useState(initialState) {
  return useReducer(null, initialState);
}

export function useEffect(create, deps) {
  return updateEffectIml(HookPassive, create, deps);
}
export function useLayoutEffect(create, deps) {
  return updateEffectIml(HookLayout, create, deps);
}
function updateEffectIml(hookFlags, create, deps) {
  const hook = updateWorkInProgressHook();
  const effect = { hookFlags, create, deps };
  // 更新阶段检查deps的变化
  if (currentHook) {
    if (deps) {
      const prevDeps = currentHook.memorizedState.deps;
      if (areHookInputsEqual(deps, prevDeps)) {
        return;
      }
    }
  }

  hook.memorizedState = effect;
  if (hookFlags & HookPassive) {
    currentlyRenderingFiber.upDateQueueOfEffect.push(effect);
  } else if (hookFlags & HookLayout) {
    currentlyRenderingFiber.updateQueueOfLayout.push(effect);
  }
}
